home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / Filezilla Server / FileZilla_Server-0_9_41.exe / source / Service.cpp < prev    next >
C/C++ Source or Header  |  2011-11-06  |  16KB  |  638 lines

  1. // FileZilla Server - a Windows ftp server
  2.  
  3. // Copyright (C) 2002-2004 - Tim Kosse <tim.kosse@gmx.de>
  4.  
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9.  
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14.  
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. // Based upon example code from Nishant S
  20. // Original code is available under http://www.codeproject.com/system/serviceskeleton.asp
  21.  
  22. #include "stdafx.h"
  23. #include "server.h"
  24. #include "Options.h"
  25.  
  26. void ServiceMain(DWORD argc, LPTSTR *argv); 
  27. void ServiceCtrlHandler(DWORD nControlCode);
  28. BOOL UpdateServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
  29.                      DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
  30.                      DWORD dwWaitHint);
  31. BOOL StartServiceThread();
  32. DWORD ServiceExecutionThread(LPDWORD param);
  33. HANDLE hServiceThread=0;
  34. void KillService();
  35.  
  36. SERVICE_STATUS_HANDLE nServiceStatusHandle = 0; 
  37. HANDLE killServiceEvent = 0;
  38. BOOL nServiceRunning = 0;
  39. DWORD nServiceCurrentStatus = 0;
  40.  
  41. static TCHAR ServiceDisplayName[257] = _T("FileZilla Server FTP server");
  42. static TCHAR ServiceName[257] = _T("FileZilla Server");
  43.  
  44. int SetAdminPort(int port);
  45. int ReloadConfig();
  46. int CompatMain(LPCSTR lpCmdLine);
  47.  
  48. void LoadServiceName()
  49. {
  50.     COptions *pOptions = new COptions();
  51.  
  52.     CStdString name = pOptions->GetOption(OPTION_SERVICE_NAME);
  53.     if (name.size() > 0 && name.size() < 256)
  54.         _tcscpy(ServiceName, name);
  55.  
  56.     CStdString display_name = pOptions->GetOption(OPTION_SERVICE_DISPLAY_NAME);
  57.     if (display_name.size() > 0 && display_name.size() < 256)
  58.         _tcscpy(ServiceDisplayName, display_name);
  59.  
  60.     delete pOptions;
  61.  
  62. }
  63.  
  64. int SetServiceName(LPCTSTR serviceName)
  65. {
  66.     size_t len = _tcslen(serviceName);
  67.     if (!len || len > 256)
  68.         return 1;
  69.  
  70.     COptions *pOptions = new COptions();
  71.     pOptions->SetOption(OPTION_SERVICE_NAME, serviceName);
  72.     delete pOptions;
  73.  
  74.     pOptions = new COptions();
  75.     if (pOptions->GetOption(OPTION_SERVICE_NAME) != serviceName)
  76.     {
  77.         delete pOptions;
  78.         return 1;
  79.     }
  80.     delete pOptions;
  81.  
  82.     return 0;
  83. }
  84.  
  85. int SetServiceDisplayName(LPCTSTR serviceDisplayName)
  86. {
  87.     size_t len = _tcslen(serviceDisplayName);
  88.     if (!len || len > 256)
  89.         return 1;
  90.  
  91.     COptions *pOptions = new COptions();
  92.     pOptions->SetOption(OPTION_SERVICE_DISPLAY_NAME, serviceDisplayName);
  93.     delete pOptions;
  94.  
  95.     pOptions = new COptions();
  96.     if (pOptions->GetOption(OPTION_SERVICE_DISPLAY_NAME) != serviceDisplayName)
  97.     {
  98.         delete pOptions;
  99.         return 1;
  100.     }
  101.     delete pOptions;
  102.  
  103.     return 0;
  104. }
  105.  
  106. int APIENTRY WinMain(HINSTANCE hInstance,
  107.                      HINSTANCE hPrevInstance,
  108.                      LPSTR     lpCmdLine,
  109.                      int       nCmdShow )
  110. {
  111.     BOOL bNT = FALSE;
  112.     BOOL bInstalled = FALSE;
  113.     BOOL dwCurrentState = 0;
  114.     
  115.     int nAction = 0;
  116.     if (lpCmdLine[0] == '/' || lpCmdLine[0] == '-')
  117.     {
  118.         lpCmdLine++;
  119.         if (strlen(lpCmdLine) >= 6 && !strncmp(lpCmdLine, "compat", 6))
  120.         {
  121.             lpCmdLine += 6;
  122.             while (lpCmdLine[0] == ' ')
  123.                 lpCmdLine++;
  124.             return CompatMain(lpCmdLine);
  125.         }
  126.         else if (!strcmp(lpCmdLine, "install"))
  127.             nAction = 1;
  128.         else if (!strcmp(lpCmdLine, "uninstall"))
  129.             nAction = 2;
  130.         else if (!strcmp(lpCmdLine, "start"))
  131.             nAction = 3;
  132.         else if (!strcmp(lpCmdLine, "stop"))
  133.             nAction = 4;
  134.         else if (!strcmp(lpCmdLine, "install auto"))
  135.             nAction = 5;
  136.         else if (strlen(lpCmdLine) >= 10 && !strncmp(lpCmdLine, "adminport ", 10))
  137.             nAction = 6;
  138.         else if (!strcmp(lpCmdLine, "reload-config"))
  139.             nAction = 7;
  140.         else if (!strncmp(lpCmdLine, "servicename ", 12))
  141.             return SetServiceName(CStdString(lpCmdLine + 12));
  142.         else if (!strncmp(lpCmdLine, "servicedisplayname ", 19))
  143.             return SetServiceDisplayName(CStdString(lpCmdLine + 19));
  144.     }
  145.  
  146.     LoadServiceName();
  147.  
  148.     if (nAction == 6)
  149.         return SetAdminPort(atoi(lpCmdLine + 10));
  150.     else if (nAction == 7)
  151.         return ReloadConfig();
  152.  
  153.     SC_HANDLE hService, hScm;
  154.     hScm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
  155.     
  156.     if (hScm)
  157.     {
  158.         bNT = TRUE;
  159.         hService = OpenService(hScm, ServiceName, GENERIC_READ);
  160.         if (hService)
  161.         {
  162.             bInstalled = TRUE;
  163.  
  164.             SERVICE_STATUS ServiceStatus;
  165.             if (QueryServiceStatus(hService, &ServiceStatus))
  166.             {
  167.                 dwCurrentState = ServiceStatus.dwCurrentState;
  168.                 if (dwCurrentState == SERVICE_START_PENDING)
  169.                 {
  170.                     CloseServiceHandle(hService);
  171.                     CloseServiceHandle(hScm);
  172.                     
  173.                     const SERVICE_TABLE_ENTRY servicetable[]=
  174.                     {
  175.                         {ServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},
  176.                         {NULL,NULL}
  177.                     };
  178.                     BOOL success;
  179.                     success=StartServiceCtrlDispatcher(servicetable);
  180.                     if (!success)
  181.                     {
  182.                         int nError=GetLastError();
  183.                         TCHAR buffer[1000];
  184.                         _stprintf(buffer, _T("StartServiceCtrlDispatcher failed with error %d"), nError);
  185.                         MessageBox(0, buffer, _T("Error while starting service"), MB_OK);
  186.                         //error occured
  187.                     }
  188.                     return 0;
  189.                 }
  190.             }
  191.  
  192.             CloseServiceHandle(hService);
  193.         }
  194.         CloseServiceHandle(hScm);
  195.     }
  196.     else
  197.     {
  198.         if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  199.         {
  200.             lpCmdLine--;
  201.             return CompatMain(lpCmdLine);
  202.         }
  203.     }
  204.         
  205.     if (!bInstalled)
  206.     {
  207.         if (nAction==1 || nAction==5 || (nAction == 0 && MessageBox(0, _T("Install Service?"), _T("Question"), MB_YESNO|MB_ICONQUESTION)==IDYES))
  208.         {
  209.             hScm=OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
  210.             if(!hScm)
  211.             {
  212.                 return 1;
  213.             }
  214.             int nStartMode = (nAction==5)?SERVICE_AUTO_START:SERVICE_DEMAND_START;
  215.             if (!nAction)
  216.                 if (MessageBox(0, _T("Autostart service?"), _T("Question"), MB_YESNO|MB_ICONQUESTION)==IDYES)
  217.                     nStartMode = SERVICE_AUTO_START;
  218.             TCHAR buffer[MAX_PATH + 3];
  219.             buffer[0] = '"';
  220.             DWORD written = GetModuleFileName(0, buffer + 1, MAX_PATH);
  221.             if (!written)
  222.             {
  223.                 CloseServiceHandle(hScm);
  224.  
  225.                 MessageBox(0, _T("Failed to get own executable path"), _T("Could not install server"), MB_ICONSTOP);
  226.                 return 1;
  227.             }
  228.             buffer[written + 1] = '"';
  229.             buffer[written + 2] = 0;
  230.  
  231.             hService=CreateService(hScm, ServiceName,
  232.                 ServiceDisplayName,
  233.                 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, nStartMode,
  234.                 SERVICE_ERROR_NORMAL,
  235.                 buffer,
  236.                 0, 0, 0, 0, 0);
  237.             if(!hService)
  238.             {
  239.                 CloseServiceHandle(hScm);
  240.                 return 1;
  241.             }
  242.             CloseServiceHandle(hService);
  243.             CloseServiceHandle(hScm);
  244.             dwCurrentState = SERVICE_STOPPED;
  245.         }
  246.         else
  247.             return 0;
  248.     }
  249.         
  250.     if (dwCurrentState == SERVICE_STOPPED && (nAction==3 || (nAction == 0 && MessageBox(0, _T("Start server?"), _T("Question"), MB_YESNO|MB_ICONQUESTION)==IDYES)))
  251.     {
  252.         SC_HANDLE hService,hScm;
  253.         hScm=OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
  254.         if(!hScm)
  255.         {
  256.             return 1;
  257.         }
  258.         hService=OpenService(hScm, ServiceName, SERVICE_ALL_ACCESS);
  259.         if(!hService)
  260.         {
  261.             CloseServiceHandle(hScm);
  262.             return 1;
  263.         }
  264.         StartService(hService, 0, NULL);
  265.         CloseServiceHandle(hService);
  266.         CloseServiceHandle(hScm);
  267.         return 0;
  268.     }
  269.  
  270.     if (dwCurrentState == SERVICE_STOPPED && (nAction==2 || (nAction == 0 && MessageBox(0, _T("Uninstall Service?"), _T("Question"), MB_YESNO|MB_ICONQUESTION)==IDYES)))
  271.     {
  272.         SC_HANDLE hService,hScm;
  273.         hScm=OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
  274.         if(!hScm)
  275.         {
  276.             return 1;
  277.         }
  278.         hService=OpenService(hScm, ServiceName, SERVICE_ALL_ACCESS);
  279.         if(!hService)
  280.         {
  281.             CloseServiceHandle(hScm);
  282.             return 1;
  283.         }
  284.         DeleteService(hService);
  285.         CloseServiceHandle(hService);
  286.         CloseServiceHandle(hScm);
  287.         return 0;
  288.     }
  289.  
  290.     if (dwCurrentState != SERVICE_STOPPED && (nAction==4 || (nAction == 0 && MessageBox(0, _T("Stop Server?"), _T("Question"), MB_YESNO|MB_ICONQUESTION)==IDYES)))
  291.     {
  292.         SC_HANDLE hService,hScm;
  293.         hScm=OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
  294.         if(!hScm)
  295.         {
  296.             return 1;
  297.         }
  298.         hService=OpenService(hScm, ServiceName, SERVICE_ALL_ACCESS);
  299.         if(!hService)
  300.         {
  301.             CloseServiceHandle(hScm);
  302.             return 1;
  303.         }
  304.         SERVICE_STATUS status;
  305.         ControlService(hService, SERVICE_CONTROL_STOP, &status);
  306.         CloseServiceHandle(hService);
  307.         CloseServiceHandle(hScm);
  308.         return 0;
  309.     }
  310.         
  311.     if (dwCurrentState == SERVICE_STOPPED)
  312.         return 0;
  313.  
  314.     return 0;
  315. }
  316.  
  317. void ServiceMain(DWORD argc, LPTSTR *argv)
  318. {
  319.     LoadServiceName();
  320.  
  321.     BOOL success;
  322.     nServiceStatusHandle = RegisterServiceCtrlHandler(ServiceName,
  323.         (LPHANDLER_FUNCTION)ServiceCtrlHandler);
  324.     if (!nServiceStatusHandle)
  325.         return;
  326.  
  327.     success = UpdateServiceStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 3000);
  328.     if (!success)
  329.         return;
  330.  
  331.     killServiceEvent = CreateEvent(0, TRUE, FALSE, 0);
  332.     if (killServiceEvent == NULL)
  333.         return;
  334.  
  335.     success = UpdateServiceStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);
  336.     if (!success)
  337.         return;
  338.  
  339.     success = StartServiceThread();
  340.     if (!success)
  341.         return;
  342.  
  343.     nServiceCurrentStatus = SERVICE_RUNNING;
  344.     success = UpdateServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
  345.     if (!success)
  346.         return;
  347.  
  348.     WaitForSingleObject(killServiceEvent, INFINITE);
  349.     CloseHandle(killServiceEvent);
  350.     WaitForSingleObject(hServiceThread, INFINITE);
  351.     CloseHandle(hServiceThread);
  352.     UpdateServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);
  353. }
  354.  
  355. BOOL UpdateServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
  356.                      DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
  357.                      DWORD dwWaitHint)
  358. {
  359.     BOOL success;
  360.     SERVICE_STATUS nServiceStatus;
  361.     nServiceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
  362.     nServiceStatus.dwCurrentState=dwCurrentState;
  363.     if(dwCurrentState==SERVICE_START_PENDING)
  364.     {
  365.         nServiceStatus.dwControlsAccepted=0;
  366.     }
  367.     else
  368.     {
  369.         nServiceStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP            
  370.             |SERVICE_ACCEPT_SHUTDOWN;
  371.     }
  372.     if(dwServiceSpecificExitCode==0)
  373.     {
  374.         nServiceStatus.dwWin32ExitCode=dwWin32ExitCode;
  375.     }
  376.     else
  377.     {
  378.         nServiceStatus.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;
  379.     }
  380.     nServiceStatus.dwServiceSpecificExitCode=dwServiceSpecificExitCode;
  381.     nServiceStatus.dwCheckPoint=dwCheckPoint;
  382.     nServiceStatus.dwWaitHint=dwWaitHint;
  383.  
  384.     success=SetServiceStatus(nServiceStatusHandle,&nServiceStatus);
  385.     if(!success)
  386.     {
  387.         KillService();
  388.         return success;
  389.     }
  390.     else
  391.         return success;
  392. }
  393.  
  394. BOOL StartServiceThread()
  395. {    
  396.     DWORD id;
  397.     hServiceThread=CreateThread(0,0,
  398.         (LPTHREAD_START_ROUTINE)ServiceExecutionThread,
  399.         0,0,&id);
  400.     if(hServiceThread==0)
  401.     {
  402.         return false;
  403.     }
  404.     else
  405.     {
  406.         nServiceRunning=true;
  407.         return true;
  408.     }
  409. }
  410.  
  411. void KillService()
  412. {
  413.     if (hMainWnd)
  414.         PostMessage(hMainWnd, WM_CLOSE, 0, 0);
  415.     nServiceRunning = false;
  416. }
  417.  
  418.  
  419. static BOOL CALLBACK SendReloadConfigProc(HWND hwnd, LPARAM lParam)
  420. {
  421.     int* res = (int*)lParam;
  422.  
  423.     TCHAR buffer[100];
  424.  
  425.     if (!GetClassName(hwnd, buffer, 100))
  426.         return TRUE;
  427.  
  428.     if (_tcscmp(buffer, _T("FileZilla Server Helper Window")))
  429.         return TRUE;
  430.  
  431.     if (!GetWindowText(hwnd, buffer, 100))
  432.         return TRUE;
  433.  
  434.     if (_tcscmp(buffer, _T("FileZilla Server Helper Window")))
  435.         return TRUE;
  436.  
  437.     PostMessage(hwnd, WM_FILEZILLA_RELOADCONFIG, 0, 0);
  438.  
  439.     *res = 0;
  440.  
  441.     return TRUE;
  442. }
  443.  
  444.  
  445. int SendReloadConfig()
  446. {
  447.     int res = 1;
  448.     EnumWindows(SendReloadConfigProc, (LPARAM)&res);
  449.  
  450.     return res;
  451. }
  452.  
  453.  
  454. void ServiceCtrlHandler(DWORD nControlCode)
  455. {
  456.     BOOL success;
  457.     switch(nControlCode)
  458.     {    
  459.     case SERVICE_CONTROL_SHUTDOWN:
  460.     case SERVICE_CONTROL_STOP:
  461.         nServiceCurrentStatus=SERVICE_STOP_PENDING;
  462.         success=UpdateServiceStatus(SERVICE_STOP_PENDING,NO_ERROR,0,1,3000);
  463.         KillService();        
  464.         return;
  465.     case 128:
  466.         SendReloadConfig();
  467.         break;
  468.     default:
  469.         break;
  470.     }
  471.     UpdateServiceStatus(nServiceCurrentStatus,NO_ERROR,0,0,0);
  472. }
  473.  
  474. DWORD ServiceExecutionThread(LPDWORD param)
  475. {
  476.     // initialize Winsock library
  477.     BOOL res=TRUE;
  478.     WSADATA wsaData;
  479.     
  480.     WORD wVersionRequested = MAKEWORD(1, 1);
  481.     int nResult = WSAStartup(wVersionRequested, &wsaData);
  482.     if (nResult != 0)
  483.         res=FALSE;
  484.     else if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
  485.     {
  486.         WSACleanup();
  487.         res=FALSE;
  488.     }
  489.  
  490.     if(!res)
  491.     {
  492.         SetEvent(killServiceEvent);
  493.         UpdateServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);
  494.         return 0;
  495.     }
  496.  
  497.     CServer *pServer = new CServer;
  498.     VERIFY(pServer->Create());
  499.  
  500.     if (!nServiceRunning)
  501.         PostQuitMessage(0);
  502.     
  503.     MSG msg;
  504.     while (GetMessage(&msg, 0, 0, 0))
  505.     {
  506.         TranslateMessage(&msg);
  507.         DispatchMessage(&msg);
  508.     }
  509.  
  510.     delete pServer;
  511.     WSACleanup();
  512.  
  513.     SetEvent(killServiceEvent);
  514.     return 0;
  515. }
  516.  
  517. int SetAdminPort(int nAdminPort)
  518. {
  519.     if (nAdminPort < 1 || nAdminPort > 65535)
  520.         return 1;
  521.  
  522.     COptions *pOptions = new COptions();
  523.     pOptions->SetOption(OPTION_ADMINPORT, nAdminPort);
  524.     delete pOptions;
  525.  
  526.     pOptions = new COptions();
  527.     if (pOptions->GetOptionVal(OPTION_ADMINPORT) != nAdminPort)
  528.     {
  529.         delete pOptions;
  530.         return 1;
  531.     }
  532.     delete pOptions;
  533.  
  534.     return 0;
  535. }
  536.  
  537. int ReloadConfig()
  538. {
  539.     int res = SendReloadConfig();
  540.  
  541.     SC_HANDLE hService, hScm;
  542.     hScm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
  543.  
  544.     if (hScm)
  545.     {
  546.         hService = OpenService(hScm, ServiceName, SERVICE_USER_DEFINED_CONTROL);
  547.         if (hService)
  548.         {
  549.             SERVICE_STATUS status;
  550.             res |= ControlService(hService, 128, &status) == 0;
  551.             CloseServiceHandle(hService);
  552.         }
  553.         CloseServiceHandle(hScm);
  554.     }
  555.  
  556.     return !res;
  557. }
  558.  
  559. int CompatMain(LPCSTR lpCmdLine)
  560. {
  561.     int nAction = 0;
  562.  
  563.     if (lpCmdLine[0] == '/' || lpCmdLine[0] == '-')
  564.     {
  565.         lpCmdLine++;
  566.         if (!strcmp(lpCmdLine, "start"))
  567.             nAction = 1;
  568.         else if (!strcmp(lpCmdLine, "stop"))
  569.             nAction = 2;
  570.         else if (strlen(lpCmdLine) >= 10 && !strncmp(lpCmdLine, "adminport ", 10))
  571.             nAction = 3;
  572.         else if (!strcmp(lpCmdLine, "install"))
  573.             return 0;
  574.         else if (!strcmp(lpCmdLine, "uninstall"))
  575.             return 0;
  576.         else if (!strcmp(lpCmdLine, "install auto"))
  577.             return 0;
  578.         else if (!strcmp(lpCmdLine, "reload-config"))
  579.             nAction = 4;
  580.     }
  581.  
  582.     if (nAction == 3)
  583.         return SetAdminPort(atoi(lpCmdLine + 10));
  584.     else if (nAction == 4)
  585.         return ReloadConfig();
  586.  
  587.     HWND hWnd = FindWindow(_T("FileZilla Server Helper Window"), _T("FileZilla Server Helper Window"));
  588.     if (nAction == 1 && hWnd)
  589.         return 0;
  590.     else if (nAction==2 && !hWnd)
  591.         return 0;
  592.     
  593.     if (!hWnd && (nAction == 1 || (nAction == 0 && MessageBox(0, _T("Start Server?"), _T("Question"), MB_YESNO|MB_ICONQUESTION)==IDYES)))
  594.     {
  595.         // initialize Winsock library
  596.         BOOL res=TRUE;
  597.         WSADATA wsaData;
  598.         
  599.         WORD wVersionRequested = MAKEWORD(1, 1);
  600.         int nResult = WSAStartup(wVersionRequested, &wsaData);
  601.         if (nResult != 0)
  602.             res=FALSE;
  603.         else if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
  604.         {
  605.             WSACleanup();
  606.             res=FALSE;
  607.         }
  608.         
  609.         if(!res)
  610.         {
  611.             return 1;
  612.         }
  613.         
  614.         CServer *pServer = new CServer;
  615.         VERIFY(pServer->Create());
  616.         
  617.         MSG msg;
  618.         while (GetMessage(&msg, 0, 0, 0))
  619.         {
  620.             TranslateMessage(&msg);
  621.             DispatchMessage(&msg);
  622.         }
  623.         
  624.         delete pServer;
  625.         WSACleanup();
  626.         return 0;
  627.     }        
  628.     else if (hWnd && (nAction == 2 || (nAction == 0 && MessageBox(0, _T("Stop Server?"), _T("Question"), MB_YESNO|MB_ICONQUESTION)==IDYES)))
  629.     {
  630.         SendMessage(hWnd, WM_CLOSE, 0, 0);
  631.         if (GetLastError())
  632.             return 1;
  633.         else
  634.             return 0;
  635.     }
  636.     
  637.     return 1;
  638. }